TFG

Indice

Introducción

Metodología

Para la realización de este trabajo voy a seguir la metodología estandar CRISP-DM.

Cross Industry Standard Process for Data Mining (CRISP-DM) es un proceso iterativo de creación de software, centrado en el análisis de datos, dividido en 6 fases:

Business Understanding

En esta fase se intenta clarificar el problema a resolver al igual que los objetivos y limitaciones de nuestra solución.

Data Understanding

En esta fase tenemos que obtener nuestros datos, explorarlos y verificar su calidad.

Data Preparation

En esta fase limpiaremos y formatearemos los datos para maximizar su potencial.

Modeling

En esta fase estudiaremos diferentes formas de realizar los modelos de recomendación y diseñare el modelo.

Evaluation

En esta fase estudiaremos el funcionamiento del modelo

Deployment

En esta fase se detallan los pasos de implementación del sistema en un ambiente profesional y las posibles mejoras.

Drawing

Phase 1 of the CRISP-DM Process Model: Business Understanding

El objetivo de este Trabajo de Fin de Grado es realizar un sistema de recomendación de películas basado en contenidos (Content-based recommender system), con verificación de recomendaciones basadas en las visualizaciones de otros usuarios.

Este trabajo no tiene un fin comercial. De todos modos, su objetivo comercial sería estudiar las técnicas de sistemas de recomendación y proporcionar una solucíon propia a este problema.

La restricción principal de este trabajo es el tiempo.

Debe ser presentado cualquiera de las siguientes tres convocatorias, Febrero, Junio o Septiembre.

El impacto de este trabajo será a nivel académico y de demostración de las tecnologías actuales de ML y de sistemas de codificación del lenguaje natural.

Phase 2 of the CRISP-DM Process Model: Data Understanding

2.1 Gathering data

La pagina web de metacritic es un sitio web que recopila reseñas de álbumes de música, videojuegos, películas, programas de televisión y libros.

Para cada categoría de entretenimiento (musica, videojuegos, libros ...), Metacritic dispone de un top donde se encuentran todos los elementos organizados por nota.

En concreto, me voy a centrar en el top de películas (https://www.metacritic.com/browse/movies/score/metascore/all/filtered?page=0).

Este top está dispuesto (actualmente) en 145 páginas, cada uno con entradas correspondientes a 100 películas.

El conjunto de datos ha sido recogido por mi utilizando un programa de webscrapping realizado en python.

En concreto el programa de webscrapping sigue el siguiente esquema:

DiccionarioPeliculas=[]

Para cada numero x de 1 a 145:

    pagina= descargarHTMLPagina(x);

    Para cada numero y de 1 a 100:

        pelicula = descargarHTMLPelicula(y)

        datosPelicula=procesarPelicula(pelicula)

        DiccionarioPeliculas.añadir(datosPelicula)

Para completar nuestra base de datos, nos interesaría mucho disponer de las reviews específicas de los usuarios para cada película que hemos recogido previamente.

Por lo tanto, usando otro programa de webscrapping realizaríamos la siguiente tarea:

PeliculasDeseadas = DiccionarioPeliculas

DiccionarioReviews=[]

Para cada pelicula en DiccionarioPeliculas:

    HTML = descargarHTMLPelicula(pelicula)

    RCs = procesarReviewsCriticos(HTML)

    RUs = procesarReviewsUsers(HTML)

    DiccionarioReviews.añadir(RCs)

    DiccionarioReviews.añadir(RUs)



PENDIENTE: #EXPLICAR EN MAYOR DETALLE EL SCRAPPER

2.2 Describing the data

Primero importaré las librerías necesarias y los datasets de películas y reviews que hemos recopilado en el apartado anterior.

Habiendo importado los datasets a un dataframe de la librería pandas correctamente, usaré el info para mostrar el número de entradas y los atributos de cada dataset.

Como podemos ver, disponemos de 13255 entradas con 12 columnas.

Solo 4 de estas columnas son variables discretas, rating, year of release, runtime y rank.

   Rating contiene la nota de 0 a 10 impuesta por los usuarios.

   Rank contiene la posición 1-15000 en la que esta película (impuesto por metacritic)

   Year contiene el año de salida de la película.

   Runtime contiene la duración de la película.


Es esperable que los atributos rating y rank esten fuertemente correlados ya que expresan información muy parecida. Esta afirmación la comprobaré mas tarde, ya que si el valor de correlación es muy alto podríamos considerar un solo atributo.

Por otro lado las variables categóricas son las siguientes:

    Title: contiene el titulo de la película.

    age_rating: indica la edad mínima recomendada para la visualización. Posteriormente haré un análisis para representarla como un entero.

    genre: indica el género.

    director: nombre del director principal de la película.

    producer: nombre de la productora.

    actor: nombre del actor principal de la película.

    description: parrafo con la descripción de la película.

    img: url de la carátula de la película.

    url: url de la página de metacritic donde se describe la película.


Por otro lado, la composición de nuestro dataset de reviews es la siguiente:

Como podemos ver tiene 5 atributos.

Title: string que contiene el nombre de la película que se está puntuando.

User: string que contiene el nombre de usuario del autor de la review.

Type: variable que identifica si el autor es un "reviewer profesional" o un usuario de la web.

Grade: nota de la review.

Review: string que contiene la valoración de la película.

2.3 Exploring data

Como podemos observar, nuestro dataset está compuesto por películas dispuestas en 22 géneros.

El drama es el género más común por grán mayoría. Seguido por acción Acción, documentales y biografías.

Como no vamos a realizar una predicción de genéneros de películas, en principio, este desbalanceo no presentará un problema en el futuro.

Por otra parte, ratings de edad de las películas se disponen de la siguiente forma:

Los años de salida siguen la siguiente distribución

Como podemos observar, desde el año 2000 a habido un crecimiento lineal en la producción de películas, a excepción de 2 parones en los siguientes años:

Para mostrar el tiempo de ejecución voy a usar un diagrama de "caja y bigotes" o boxplot.

El resultado es el siguiente:

Como podemos observar, la mediana en cuanto a duración es 101 minutos.

Los valores extremos se situan en 62 y 144 minutos. Las duraciones fuera de este rango se consideran datos atípicos o outliers.

También vamos a visualizar los 25 actores principales más comunes.

Con respecto a las notas de las reviews, voy a realizar un boxplot para representar las notas de los usuarios y los reviewers.

Como podemos observar, las notas de los reviewers se encuentran en el rango de 0 a 100 y las de los usuarios, de 0 a 10.

Por lo tanto, esto lo tendremos que tener en cuenta en el apartado de data preparation.

2.4 Verifying data quality

Para verificar la calidad de nuestros conjuntos de datos verificaré los siguientes criterios:

2.4.1 Unicidad:

Para comprobar la unicidad de nuestros conjuntos de datos podemos utilizar el siguiente método de la librería pandas

Pandas.DataFrame.duplicated() 

Este método, dado un dataframe, devuelve, para cada una de las entradas, si es única o no.

Agrupando este resultado con la función value_counts() obtenemos el siguiente resultado.

Como podemos observar, existen 423 reviews duplicadas y 0 películas duplicadas.

Por lo tanto, podemos ejecutar la función drop_duplicates() de los dataframes de la librería pandas y eliminar estos valores repetidos.

Si comprobasemos ahora los resultados de la función anterior obtendriamos 0 repetidos.

2.4.2 Completitud:

Considero que tanto el dataset de reviews como el de películas son muy completos en cuanto a contenido y numero de entradas.

Ambos datasets contienen todas las entradas en cuanto a películas o críticas disponibles en metacritic.

No existe ninguna dataset publica de Metacritic para la sección de películas. Por lo tanto compararé mi dataset con los 3 datasets de reviews de películas mas "relevantes" según el buscador de Kaggle:

2.4.3 Validez:

El conjunto de datos de Películas es válido ya que ha sido creado por empleados de metacritic y solo contiene datos factuales.

Por otro lado, algunas atributos son nulos o están por determinar si la película no ha salido todavía al público.

El conjunto de datos de reviews si que puede presentar problemas de validez debido a que las reviews de los usuarios no son filtradas.

2.4.4 Consistencia:

Durante el estudio exploratorio del conjunto de datos he encontrado las siguientes inconsistencias:

Las clasificaciones de edad de cada película usan las convenciones particulares de cuando esa película fue grabada.

Por lo tanto, disponemos de 24 labels categóricas que podrían ser remplazadas por unos pocos números enteros.

Las reviews de los criticos estan sobre 100 en metacritic y las de los users sobre 10.

Algunas reviews incluyen la string "This review contains spoilers, click expand to view." indicando que esa review tiene spoilers. Este patrón será eliminado del contenido de la review y indicado en una nueva columna de nuestro dataset.

Como hemos visto en el análisis exploratorio, las reviews son mayoritariamente en inglés. De todos modos, existen algunas reviews que su contenido de palabras en inglés es muy bajo, por lo tanto, están en otro idioma (o repletas de faltas de ortografía).

2.4.5 Precisión:

El dataset de películas es preciso ya que ha sido realizado por profesionales encargados de gestionar la página de metacritic.

El dataset de reviews tiene un contendio subjetivo, por lo tanto no podemos medir su precisión. De todos modos cabe destacar que las reviews esta categorizadas por si son de Reviewers o de Usuarios.

Phase 3 of the CRISP-DM Process Model: Data Preparation

3.1 Cleaning the data

3.1.1 Procesado de la clasificación de edad.

Como hemos podido observar en el gráfico anterior, esta columna está muy desbalanceada, a demas tiene un alto contenido de valores nulos. De todos modos, vamos a realizar data wrangling de forma que agrupamos estas variables categóricas en edades como numeros enteros.

Como podemos observar, hemos eliminado las variables categóricas y el resultado es mucho mas claro.

Seguimos teniendo una gran cantidad de valores sin calificar (valor -1 en el eje x), sin embargo, como la gran mayoría de valores se encuentran entre 13 y 18 creo que sería buena idea sustituirlo por el valor medio.

Esta distribución sería más apropiada teniendo en cuenta los datos no nulos.

3.1.2 Re-escalado de notas de usuarios

Como hemos visto en el apartado 2.3 Exploring data, las calificaciones realizadas por los usuarios se encuentran en el rango de 0 a 10 y las de los críticos en el rango de 0 a 100.

Por lo tanto, vamos a multiplicar las calificaciones de los usuarios por 10 para que todas las calificaciones se encuentren en el mismo intervalo.

Tras aplicar una función lambda, podemos comprobar el resultado con el mismo boxplot que antes.

3.1.3 Limpieza de contenido de reviews con spoilers.

Muchas de las reviews de nuestro dataset contienen spoilers.

Metacritic incluye la siguiente subcadena en las reviews con spoilers.

"This review contains spoilers, click expand to view."

Eliminaremos esta subcadena de nuestras reviews para eliminar un posible efecto negativo en el algoritmo de vectorización.

De todos modos, añadiremos una nueva columna a nuestro dataset que indique si la review contiene spoilers o no.

Para comprobar si el filtrado ha funcionado correctamente volveremos a ejecutar el método contains agrupado por la función value_counts()

3.1.4 Indicación de idioma inglés en las reviews.

Como hemos comprobado previamente, el contenido de las reviews se encuentra escrito mayoritariamente en inglés.

El metodo programado anteriormente nos indicaba que porcentaje de la review está en inglés.

Para no tener que designar 'a ojo' un límite que separe el contenido en inglés del de otros idiomas vamos a delegar esta tarea en diferentes librerías de procesado de lenguaje capaces de reconocer el idioma de un texto.

La metodología que voy a seguir es:

Si la mayoría de ellas (2 de 3 librerías) detectan el mismo idioma, entonces, clasificaríamos el idioma de la review como el idioma coincidente.

Ahora ejecutaríamos el siguiente código para categorizar el lenguaje de las reviews.

Este bucle tarda alrededor de una hora en finalizar, por lo tanto usando la indicación

%%script false --no-raise-error 

indico que esa celda de código no va a ser ejecutada.

En una ejecución previa, guardé su contenido como CSV y desde ese momento, leo un fichero con su contenido.

Despues de añadir el idioma a nuestro dataframe podemos ver como se distribuyen las reviews.

3.1.5 Uso exclusivo de letras minúsculas.

3.1.6 Uso exclusivo de caracteres ascii

3.1.7 Eliminación de stopwords.

Stopwords son conectores que carecen de valor gramatical (the, and, to,that ...)

Generalmente durante el entrenamiento de los embedders esto se han tenido en cuenta. Como indica el paper(https://proceedings.neurips.cc/paper/2013/file/9aa42b31882ec039965f3c4923ce901b-Paper.pdf):

We show that subsampling of frequent words during training results in a significant speedup (around 2x - 10x), and improves accuracy of the representations of less frequent words.

En caso que quisiesemos eliminarlas podríamos restar a nuestras review la intersección de la review con el siguiente conjunto proporcionado por NLTK (nltk.download('stopwords')):

    set(stopwords.words("english"))

3.2 Constructing the clean dataset.

Tras haber limpiado nuestros datasets podemos exportarlos en nuevos ficheros.

Phase 4 of the CRISP-DM Process Model: Modeling

4.1 Selecting modeling techniques

En este apartado nos vamos a centrar en explicar que es un embedding, las diferentes técnicas de generación de embeddings y como pensamos utilizarlo en el recomendador de películas.

4.1.1 Embeddigns

Los modelos de machine learning, por lo general, utilizan vectores como parametros de entrada.

Por lo tanto, cuando trabajamos con palabras o texto, lo primero que necesitamos hacer es convertir estas strings a vectores.

Una de las grandes ventajas que presentan las técnicas de embeddings, es que el siginificado de las palabras se ve reflejado en la diferentes carácterísticas de los vectores.

4.1.1.1 Explicación formal word2vec

La red neuronal word2vec fue una de las primeras victorias en el campo del NLP con redes neuronales.

Word2vec es capaz de, dado una palabra, retornar un vector que codifica esa palabra.

La copa oculta tiene N neuronas.

La capa de salida vuelve a ser un vector one hot de dimension V con una distriubcion de probabilidad realizada usando softmax.

La capa de entrada es un vector one hot encoded de longitud V.

La capa oculta contiene N neuronas.

La capa de salida contiene C distribuciones de probabilidad con V probilidades cada una (una para cada palabra)(equivalente al de entrada) cuyos valores son los valores porcesados por softmax.

En ambos casos las redes neuronales se entrenan usando softmax.

Por último, uno de los problemas que nos presenta Word2Vec es que ha sido diseñado para procesar embeddings palabra por palabra. Por lo tanto, para realizar el embedding de un texto, lo que haré será realizar la media de todos los vectores que lo componen.

4.1.1.2 Explicación formal Bert

Why not finetunning bert: finetunning for labeled data

4.1.1.3 Explicación formal Glove/FastText

4.1.2 Recommender System

Provisionalemente: Como sistema de recomendación, el planteamiento a seguir es buscar las películas tales que la similitud del coseno de los diferentes vectores es máxima.

Idealmente: hacer one hot del genero, añadir los valores numéricos como recomendación y nota y vectores de embedding y pasarlos a knn, solicitar al modelo los K más cercanos.</font>

4.2 Building model(s)

4.2.1.1 word2vec model

Para realizar nuestro modelo basado en Word2Vec voy a seguir el siguiente proceso:

Primero importamos las librerías necesarias.

Cargamos nuestro dataset de películas, y por si acaso (no debería haber ninguna), eliminamos las películas con descripciones nulas.

Realizamos un corpus de palabras que contenga todas las reviews de nuestro dataset separadas en palabras.

También obtenemos el modelo básico de word2vec "GoogleNews-vectors-negative300". Este modelo fue entrenado por Google usando un dataset de Google News con alrededor de 100 mil millones de palabras.

Este modelo contiene vectores 300-dimensonales para 3 millones de palabras.

Como hemos explicado antes, word2vec devuelve un vector dado una palabra.

Por lo tanto, para interpretar las decripciones de las películas podemos realizar la media entre todos los vectores "palabra" de cada descripción y ver si los resultados son prometedores.

Esta es la celda de código más pesada, donde obtendríamos los vectores medios de cada descripción.

4.2.1.2 Bert default

4.2.1.3 Bert base pre-training

4.2.2 Recommender system

4.2.2.1 KNN entre embeddings

Llegados a este punto podemos importar los vectores que habíamos calculado en una ejecución anterior y empezar a ver los resultados.

Como medida de similitud entre descripciones de películas (vectores), voy a usar la distancia del coseno.

La distancia del coseno se suele utilizar como media de similitud en procesamiento de texto.

La similitud del coseno tiene en cuenta la orientación de los vectores y no la magnitud.

Habiendo descrito nuestra medida de distancia podemos, dada una película, buscar las películas que tienen descripciones más parecidas.

Visto todo el código, vamos a comprobar las recomendaciones de varias películas

Phase 5 of the CRISP-DM Process Model: Evaluation

Phase 6 of the CRISP-DM Process Model: Deployment

PENDIENTE: ¿pasar de notebook a py y hacer gui?

## BIBLIOGRAFIA

CRISP DM Pete Chapman, Julian Clinton, Randy Kerber, Thomas Khabaza, Thomas Reinartz, Colin Shearer, and Rüdiger Wirth (2000); The CRISP-DM User Guide https://www.the-modeling-agency.com/crisp-dm.pdf

Citar los 3 datasets

Metacritic top

Beautiful soup documentation

La web donde explican lo de STEM,TOR, proxy... </font>

https://stackoverflow.com/questions/39142778/python-how-to-determine-the-language

Retrain bert https://www.kaggle.com/abhishek/bertsrc